package com.sinodata.bsm.center.engine.event;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.sinodata.bsm.center.bean.EventRuleBean;
import com.sinodata.bsm.center.bean.PropertyBean;
import com.sinodata.bsm.center.cache.PropertyValueCache;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.constants.DataTypeConstants;
import com.sinodata.bsm.common.constants.SeparatorConstants;
import com.sinodata.bsm.common.utils.StringUtil;
import com.sinodata.bsm.common.vo.Event;
import com.sinodata.bsm.common.vo.Property;

/**
 * <p>
 * Description: 表格事件不可恢复事件规则组
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2013-1-15 下午1:08:33          liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see     
 */
public class TableUnresumableRuleGroup extends EventRuleGroup {

    protected static Logger logger = Logger.getLogger(TableUnresumableRuleGroup.class);

    private static PropertyValueCache propertyValueCache = SpringContextHolder.getBean(PropertyValueCache.class);

    private static String regex = "(tprop\\(\\d+,\\d+[L|l]?,)([^\\)]+)(\\))";

    /**
     * @param resId
     * @param eventTypeId
     */
    public TableUnresumableRuleGroup(Long resId, Long eventTypeId) {
        super(resId, eventTypeId);
    }

    @Override
    public List<Event> matches(Long resId, Long propId) {
        List<Event> events = new ArrayList<Event>();
        Property property = PropertyBean.get(propId).property();
        String format = property.getFormat();
        int dataTypeId = property.getDataTypeId().intValue();
        if (dataTypeId != DataTypeConstants.DATA_TYPE_OBJECT && property.getFormat() != null) {//是表格类型数据
            return events;
        }
        if (rules == null || rules.size() == 0) {
            return events;
        }
        Map<String, Event> map = new HashMap<String, Event>();//临时事件Map集合
        String result = propertyValueCache.getValue(resId, propId);

        for (Iterator<EventRuleBean> i = rules.iterator(); i.hasNext();) {
            EventRuleBean r = i.next();
            String expr = r.eventRule().getExpr(); //!tprop(8173,120201090000004L,主机用户).equals("oracle")
            String msg = r.eventRule().getMsg(); //"用户："+tprop(8173,120201090000004L,主机用户)+" 非法登陆数据库"
            Map<String, String> exprMap = StringUtil.getAllByRegex(expr, regex);
            Map<String, String> msgMap = StringUtil.getAllByRegex(msg, regex);

            String keyWord = r.eventRule().getObjectExpr();
            String[] keyWords = null;
            if (keyWord == null || "".equals(keyWord.trim())) {
                String[] formats = format.split("|");
                keyWords = new String[formats.length];
                for (int j = 0; j < formats.length; j++) {
                    keyWords[j] = j + "";
                }
            } else {
                keyWords = keyWord.trim().split(",");
            }
            if (expr == null || msg == null || "".equals(expr) || "".equals(msg)) {
                break;
            }

            String[] values = result.split(SeparatorConstants.LIN_SEPARATOR);
            for (int v = 0; v < values.length; v++) {
                String[] dataArray = values[v].split(SeparatorConstants.COL_SEPARATOR);
                r.eventRule().setExpr(build(exprMap, v));
                r.eventRule().setMsg(build(msgMap, v));
                if (r.matching()) {
                    try {
                        String objectId = resId + "_" + propId + "_";
                        for (int j = 0; j < keyWords.length; j++) {
                            int keyCol = Integer.parseInt(keyWords[j].trim());
                            objectId += dataArray[keyCol] + "_";
                        }
                        Event newEvent = r.makeEvent(objectId);
                        Event hevent = map.get(objectId);
                        if (hevent == null || hevent.getLevel() < newEvent.getLevel()) {
                            map.put(objectId, newEvent);
                        }
                    } catch (Exception e) {
                        logger.error("failed to create event ", e);
                    }
                }
                r.eventRule().setExpr(expr);
                r.eventRule().setMsg(msg);
            }
        }
        if (map.size() == 0) {
            return events;
        }
        //循环HashMap返回事件
        Iterator<String> it = map.keySet().iterator();
        while (it.hasNext()) {
            events.add(map.get(it.next()));
        }
        return events;
    }

    /**
     * 
     * 这个方法的作用有两个：
     * 1为形如：tprop(25625,120201110000003L,状态)的表达式中的字符串”状态“加上双引号，
     * 2将table的行号keyCol加到后面
     * 组成形如：tprop(25625,120201110000003L,"状态",0)的表达式以便能调用com.sinodata.bsm.center.expression.Functions中的getTablePropertyValue方法
     * @param expr
     *            原始的表达式
     * @param keyCol
     *            table的行号
     * @return
     */
    private String buildSingleExpr(String expr, int keyCol) {
        Matcher matcher = Pattern.compile(regex).matcher(expr);
        StringBuffer buffer = new StringBuffer();
        if (matcher.find()) {
            buffer.append(matcher.group(1));
            buffer.append("\"");
            buffer.append(matcher.group(2));
            buffer.append("\"");
            buffer.append("," + keyCol);
            buffer.append(matcher.group(3));
        }
        String newExpr = buffer.toString();
        return newExpr.equals("") ? expr : newExpr;
    }

    private String build(Map<String, String> map, int keyCol) {
        String expression = map.get("sum");
        if (expression != null) {
            for (String key : map.keySet()) {
                expression = expression.replace(key, buildSingleExpr(map.get(key), keyCol));
            }
        }
        return expression;
    }
}